﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace AlphaWindow
{
	public partial class Form1 : Form, ISkinnableForm
	{
		protected Graphics GFX;
		protected Bitmap BMP;
		protected BLENDFUNCTION blend = new BLENDFUNCTION();

		internal readonly static Color WindowFillColor = Color.FromArgb(153, 109, 141, 200);

		protected override CreateParams CreateParams
		{
			get
			{
				CreateParams cp = base.CreateParams;
				if (!DesignMode)
					cp.ExStyle |= 0x00080000;
				return cp;
			}
		}

		public Form1()
		{
			InitializeComponent();

			if (!DesignMode)
			{
				SetStyle(ControlStyles.DoubleBuffer, false);
				SetStyle(ControlStyles.UserPaint, true);
				SetStyle(ControlStyles.AllPaintingInWmPaint, true);
				SetStyle(ControlStyles.Opaque, true);

				blend.BlendOp = Win32Helper.AC_SRC_OVER;
				blend.BlendFlags = 0;
				blend.SourceConstantAlpha = 255;
				blend.AlphaFormat = Win32Helper.AC_SRC_ALPHA;

				Form1_Resize(null, null);
			}
		}

		public void Update(MethodInvoker callback)
		{
			if (IsDisposed || Disposing)
				return;

			try
			{
				if (this.InvokeRequired)
					this.Invoke(callback);
				else
					callback();
			}
			catch (Exception e)
			{
				MessageBox.Show(e.Message);
			}
		}

		/// <summary>
		/// Threadsafe method to call from controls when they needs to redraw form
		/// </summary>
		public void RedrawRequested()
		{
			Update(delegate
				{
					RedrawForm();
				});
		}

		private void RedrawForm()
		{
			if (Visible)
			{
				GFX.Clear(WindowFillColor);

				////!!! uncomment it for some fun
				//GFX.FillRectangle(new LinearGradientBrush(
				//						new Point(0,0), 
				//						new Point(Width, Height), 
				//						Color.FromArgb(250, 50, 50, 100), 
				//						Color.FromArgb(50, 50, 50, 100)), 0,0, Width, Height );

				RedrawBackground();

				for (int cnt = Controls.Count - 1; cnt >= 0; cnt--)
					if (Controls[cnt] is ISkinnableControl && Controls[cnt].Visible)
						((ISkinnableControl)Controls[cnt]).RedrawControl(GFX);
				else
					Controls[cnt].DrawToBitmap(BMP, new Rectangle(Controls[cnt].Left, Controls[cnt].Top, Controls[cnt].Width, Controls[cnt].Height));

				AssignGFX();
			}
		}

		protected virtual void RedrawBackground()
		{
			int W1 = Width - Skin.Main_L1.Width - Skin.Main_R1.Width;
			W1 = (int)(W1 + W1 * 0.10);
			int YL = Height - Skin.Low_L1.Height;

			GFX.DrawImage(Skin.Shadow_L, 0, Skin.Main_L1.Height, Skin.Shadow_L.Width, YL);
			GFX.DrawImage(Skin.Shadow_R, Width - Skin.Shadow_R.Width, Skin.Main_R1.Height, Skin.Shadow_R.Width, YL);

			GFX.DrawImageUnscaled(Skin.Main_L1, 0, 0);
			GFX.DrawImage(Skin.Main_M1, Skin.Main_L1.Width, 0, W1, Skin.Main_M1.Height);
			GFX.DrawImageUnscaled(Skin.Main_R1, Width - Skin.Main_R1.Width, 0);

			GFX.DrawImageUnscaled(Skin.Low_L1, 0, YL);
			GFX.DrawImage(Skin.Low_M1, Skin.Main_L1.Width, YL, W1, Skin.Low_M1.Height);
			GFX.DrawImageUnscaled(Skin.Low_R1, Width - Skin.Low_R1.Width, YL);
		}

		private void AssignGFX()
		{
			IntPtr screenDc = Win32Helper.GetDC(IntPtr.Zero);
			IntPtr memDc = Win32Helper.CreateCompatibleDC(screenDc);
			IntPtr hBitmap = IntPtr.Zero;
			IntPtr objBitmap = IntPtr.Zero;

			try
			{
				hBitmap = BMP.GetHbitmap(Color.FromArgb(0));
				objBitmap = Win32Helper.SelectObject(memDc, hBitmap);

				TSize size = new TSize(Width, Height);
				TPoint pointSource = new TPoint(0, 0);
				TPoint topPos = new TPoint(Left, Top);

				Win32Helper.UpdateLayeredWindow(Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, Win32Helper.ULW_ALPHA);
			}
			finally
			{
				Win32Helper.ReleaseDC(IntPtr.Zero, screenDc);
				if (hBitmap != IntPtr.Zero)
				{
					Win32Helper.DeleteObject(objBitmap);
					Win32Helper.DeleteObject(hBitmap);
				}
				Win32Helper.DeleteDC(memDc);
			}
		}

		private void Form1_Shown(object sender, EventArgs e)
		{
			Form1_Resize(null, null);
		}

		private void Form1_FormClosing(object sender, FormClosingEventArgs e)
		{
			if (GFX != null) GFX.Dispose();
			if (BMP != null) BMP.Dispose();
		}

		private void Form1_Resize(object sender, EventArgs e)
		{
			if (!DesignMode && Created)
			{
				if (GFX != null) GFX.Dispose();
				if (BMP != null) BMP.Dispose();

				BMP = new Bitmap(Width, Height, PixelFormat.Format32bppPArgb);
				GFX = Graphics.FromImage(BMP);

				GFX.CompositingQuality = CompositingQuality.Invalid;
				GFX.CompositingMode = CompositingMode.SourceCopy;
				GFX.SmoothingMode = SmoothingMode.None;
				GFX.InterpolationMode = InterpolationMode.NearestNeighbor;
				GFX.TextRenderingHint = TextRenderingHint.SystemDefault;

				RedrawForm();
			}
		}

		private void Form1_MouseDown(object sender, MouseEventArgs e)
		{
			if (e.Y > Height - Skin.Low_R1.Height && e.X > Width - Skin.Low_R1.Width )
			{
				Win32Helper.ReleaseCapture();
				Win32Helper.PostMessage(Handle, Win32Helper.WM_SYSCOMMAND, Win32Helper.DOSIZE8, 0);
			}
			else if (e.Y < 28)
			{
				Win32Helper.ReleaseCapture();
				Win32Helper.PostMessage(Handle, Win32Helper.WM_SYSCOMMAND, Win32Helper.DOMOVE, 0);
			}
		}

		private void pictureBox1_Click(object sender, EventArgs e)
		{
			Close();
		}

		private void button1_MouseEnter(object sender, EventArgs e)
		{
			RedrawRequested();
		}

		private void button1_MouseDown(object sender, MouseEventArgs e)
		{
			RedrawRequested();
		}

		private void alphaButton1_Click(object sender, EventArgs e)
		{

		}

	}
}
